home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * DYNAMIC_LOADER.C
- *
- * Dynamically load specified object module
- *
- * IDENTIFICATION:
- * $Header: /private/postgres/src/port/dec/RCS/dynloader.c,v 1.7 1991/12/15 02:01:25 glass Exp $
- */
-
- #include <stdio.h>
- #include <sys/exec.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
-
- #include "port.h"
- #include "tmp/c.h"
- #include "utils/log.h"
- #include "utils/fmgr.h"
-
- char *sbrk();
- char *Align();
-
- /*
- * WARNING: the exec header may show dsize = N and bsize = 0 where the
- * actual format in 'dat' and 'bss' is N - V and V.
- */
-
- static struct {
- struct exec ex;
- struct scnhdr txt;
- struct scnhdr dat;
- struct scnhdr bss;
- } hdr;
-
- /*
- * Unfortunately, the MIPS proccessor's JAL (jump and link) instruction
- * only has a 28 bit resolution (26 bits long world aligned). Therefore,
- * for dynamically loaded code in the data area (0x1000,0000) to access
- * routines in the text area, a jump table must be constructed in the
- * data area that uses the JR (jump register) instruction.
- */
-
- typedef struct {
- long ary[4];
- /*
- * lui r14,0xMMMM 0x3C0Exxxx
- * ori r14,r14,0xLLLL 0x35CExxxx
- * jr r14 0x01C00008 000000rrrrr00000... (r=01110)
- * nop 0x00000000
- */
- } AJMP;
-
- #define AJMP0 0x3C0E0000
- #define AJMP1 0x35CE0000
- #define AJMP2 0x01C00008
- #define AJMP3 0x00000000
-
- static HDRR shdr;
-
- #define a_nscns ex.ex_f.f_nscns
- #define a_symptr ex.ex_f.f_symptr
- #define a_nsyms ex.ex_f.f_nsyms
-
- #define a_tsize ex.ex_o.tsize
- #define a_dsize ex.ex_o.dsize
- #define a_bsize ex.ex_o.bsize
-
- AJMP *AJmp;
-
- DynamicFunctionList *
- dynamic_file_load(err, filename, start_address, size)
- char **err;
- char *filename;
- char **start_address;
- int *size;
-
- {
- int fd;
- int n;
- int a_strsize;
- char *ptr;
- char *p_start;
- char *p_text;
- char *p_data;
- char *p_bss;
- char *p_jmptab;
- char *p_syms;
- char *p_treloc;
- char *p_dreloc;
- char *p_breloc;
- char *p_strs;
- char *p_end;
- DynamicFunctionList *retval, *load_symbols();
-
- bzero(&hdr, sizeof(hdr));
-
- fd = open(filename, O_RDONLY, 0);
- if (fd < 0) {
- *err = "unable to open file";
- return(NULL);
- }
- n = read(fd, &hdr.ex, sizeof(hdr.ex));
- if (n != sizeof(hdr.ex) /*|| N_BADMAG(hdr)*/) {
- *err = "bad object header";
- close(fd);
- return(NULL);
- }
- if (hdr.a_nscns > 3) {
- *err = "expected 3 sections in object hdr";
- close(fd);
- return(NULL);
- }
- read(fd, &hdr.txt, hdr.a_nscns * sizeof(hdr.txt));
- lseek(fd, hdr.a_symptr, 0);
- n = read(fd, &shdr, sizeof(shdr));
- if (n != sizeof(shdr)) {
- *err = "bad sym hdr";
- close(fd);
- return(NULL);
- }
-
- /*
- * BRK enough for:
- * a_text
- * a_data
- * a_bss
- * a_syms
- * a_trsize
- * a_drsize
- * and string table
- *
- * When through relocating, BRK to remove a_syms, a_trsize, a_drsize
- * NOTE THAT NO CALLS THAT USE MALLOC() MAY BE MADE AFTER THE SBRK!
- */
-
- p_start = ptr = Align(sbrk(0));
- p_text = ptr; ptr = p_text + hdr.txt.s_size;
- p_data = ptr; ptr = p_data + hdr.dat.s_size;
- p_bss = ptr; ptr = p_bss + hdr.bss.s_size;
- p_jmptab= ptr; ptr = p_jmptab+ shdr.iextMax * sizeof(AJMP);
- p_syms = Align(ptr); ptr = p_syms + shdr.iextMax * sizeof(EXTR);
- p_treloc= Align(ptr); ptr = p_treloc + hdr.txt.s_nreloc * sizeof(Reloc);
- p_dreloc= Align(ptr); ptr = p_dreloc + hdr.dat.s_nreloc * sizeof(Reloc);
- p_breloc= Align(ptr); ptr = p_breloc + hdr.bss.s_nreloc * sizeof(Reloc);
- p_strs = Align(ptr); ptr = p_strs + shdr.issExtMax;
- p_end = Align(ptr);
-
- AJmp = (AJMP *)p_jmptab;
-
- if (brk(p_end) == -1) {
- *err = "brk() failed";
- close(fd);
- return(NULL);
- }
- n = 0;
- n += seekread("text", fd, hdr.txt.s_scnptr, p_text, hdr.txt.s_size);
- n += seekread("data", fd, hdr.dat.s_scnptr, p_data, hdr.dat.s_size);
- n += seekread("bss ", fd, hdr.bss.s_scnptr, p_bss , hdr.bss.s_size);
- n += seekread("syms", fd, shdr.cbExtOffset, p_syms, shdr.iextMax
- * sizeof(EXTR));
- n += seekread("trel", fd, hdr.txt.s_relptr, p_treloc,
- hdr.txt.s_nreloc * sizeof(Reloc));
- n += seekread("drel", fd, hdr.dat.s_relptr, p_dreloc,
- hdr.dat.s_nreloc * sizeof(Reloc));
- n += seekread("brel", fd, hdr.bss.s_relptr, p_breloc,
- hdr.bss.s_nreloc * sizeof(Reloc));
- n += seekread("strs", fd, shdr.cbSsExtOffset, p_strs, shdr.issExtMax);
- close(fd);
-
- if (n) {
- *err = "format-read error";
- if (sbrk(0) != p_end)
- elog(WARN, "dynamic_load: unexpected malloc");
- else
- brk(p_start); /* restore allocated memory */
- return(NULL);
- }
-
- /*
- * relocate
- *
- * n holds cumulative error
- */
-
- {
- EXTR *syms = (EXTR *)p_syms;
- Reloc *reloc;
- Reloc *relend;
-
- n = 0;
- reloc = (Reloc *)p_treloc;
- relend= reloc + hdr.txt.s_nreloc;
- while (reloc < relend) {
- n += relocate(p_text, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
- ++reloc;
- }
-
- reloc = (Reloc *)p_dreloc;
- relend= reloc + hdr.dat.s_nreloc;
- while (reloc < relend) {
- n += relocate(p_data, reloc, p_syms, p_strs, p_text, p_data, p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
- ++reloc;
- }
-
- reloc = (Reloc *)p_breloc;
- relend= reloc + hdr.bss.s_nreloc;
- while (reloc < relend) {
- n += relocate(p_bss, reloc, p_syms, p_strs, p_text, p_data,
- p_bss, hdr.txt.s_vaddr, hdr.dat.s_vaddr, hdr.bss.s_vaddr);
- ++reloc;
- }
- }
- if (n)
- *err = "relocate error";
-
- if (sbrk(0) != p_end) {
- elog(WARN, "unexpected malloc %08lx %08lx", sbrk(0), p_end);
- } else {
- brk(p_syms); /* destroy non essential data */
- }
- *start_address = p_start;
- *size = (long) (p_syms - p_start);
-
- retval = load_symbols(filename, p_start);
-
- return(retval);
- }
-
- relocate(base, reloc, symbase, strs, tbase, dbase, bbase, vtbase, vdbase, vbbase)
- char *base;
- Reloc *reloc;
- EXTR *symbase;
- char *strs;
- char *tbase, *dbase, *bbase;
- long vtbase, vdbase, vbbase;
- {
- char *address = tbase + reloc->r_vaddr; /* always rel to tbase */
- char *symname;
- unsigned long value;
- short n_type;
-
- fflush(stdout);
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("relocate (tdb) %08lx %08lx %08lx addr %08lx\n",
- tbase, dbase, bbase, address
- );
- #endif
-
- if (reloc->r_extern == 0) {
- symname = "<internal>";
- switch(reloc->r_symndx) {
- case R_SN_TEXT:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("local text");
- #endif
- value = (long)tbase - vtbase;
- break;
- case R_SN_DATA:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("local data");
- #endif
- value = (long)dbase - vdbase;
- break;
- case R_SN_SDATA:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("local sdata ???");
- #endif
- value = (long)bbase - vbbase;
- break;
- default:
- elog(WARN, "dynamic_loader: don't understand secton type %d",
- reloc->r_symndx
- );
- break;
- }
- } else {
- EXTR *sym = symbase + reloc->r_symndx;
- symname = strs + sym->asym.iss;
- switch(sym->asym.sc) {
- case scText:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("text symb");
- #endif
- value = (long)tbase - vtbase;
- break;
- case scData:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("data symb");
- #endif
- value = (long)dbase - vdbase;
- break;
- case scBss:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("bss symb");
- puts("????");
- #endif
- value = (long)dbase - vbbase;
- break;
- case scUndefined:
- #ifdef DYNAMIC_LOADER_DEBUG
- puts("undef symb");
- #endif
- {
- FList *fl = ExtSyms;
- char *str = strs + sym->asym.iss;
- AJMP *aj;
- #ifdef DYNAMIC_LOADER_DEBUG
- puts(str);
- #endif
-
- while (fl->name) {
- if (strcmp(fl->name, str) == 0)
- break;
- if (fl->name[0] == '_' && strcmp(fl->name + 1, str) == 0)
- break;
- ++fl;
- }
- if (fl->name == NULL)
- elog(WARN, "dynamic_loader: Illegal ext. symbol %s", str);
- value = (long)fl->func;
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("func addr %08lx\n", value);
- #endif
-
- aj = AJmp + reloc->r_symndx; /* index into jump table */
- /* create jt entry */
- aj->ary[0] = AJMP0 | ((value >> 16) & 0xFFFF);
- aj->ary[1] = AJMP1 | (value & 0xFFFF);
- aj->ary[2] = AJMP2;
- aj->ary[3] = AJMP3;
- value = (long)aj;
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("Jmp Tab Addr %08lx\n", value);
- #endif
- }
- break;
- default:
- elog(WARN, "dynamic_loader: do'na understand storage class %d",
- sym->asym.sc
- );
- break;
- }
- }
-
- switch(reloc->r_type) {
- case R_REFHALF: /* 1 16 bit reference */
- case R_REFWORD: /* 2 32 bit reference */
- elog(WARN, "dynamic_loader: reloc type? %d %s",
- reloc->r_type, symname
- );
- break;
- case R_JMPADDR: /* 3 26 bit jump ref (rel?) */
- value &= 0x0FFFFFFF;
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("ja %08lx %08lx (%08lx)\n", address, value, *(long *)address);
- #endif
- *(long *)address += (value >> 2); /* long words */
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("ja address is: %08lx\n", (*(long *)address & 0x03FFFFFF) << 2);
- #endif
- break;
- case R_REFHI: /* 4 high 16 bits */
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("rhi %08lx %08lx (%s)\n", address, value, value);
- #endif
- *(short *)(address) += (value >> 16) & 0xFFFF;
- break;
- case R_REFLO: /* 5 low 16 bits */
- #ifdef DYNAMIC_LOADER_DEBUG
- printf("rlo %08lx %08lx\n", address, value);
- #endif
- *(short *)(address) += value & 0xFFFF;
- break;
- case R_GPREL: /* 6 global pointer relative data item */
- elog(WARN, "dynamic_loader: must compile -G 0!",
- reloc->r_type, symname
- );
- break;
- case R_LITERAL: /* 7 global pointer relative literal pool item */
- elog(WARN, "dynamic_loader: reloc type? %d %s",
- reloc->r_type, symname
- );
- break;
- default:
- return(-1);
- }
- return(0);
- }
-
- seekread(seg, fd, offset, ptr, bytes)
- char *seg;
- int fd;
- int offset, bytes;
- unsigned char *ptr;
- {
- int n;
-
- n = lseek(fd, offset, 0);
- if (n != offset)
- return(-1);
- n = read(fd, ptr, bytes);
- if (n != bytes)
- return(-1);
- return(0);
- }
-
- char *
- Align(padr)
- char *padr;
- {
- long adr = ((long)padr + 3) & ~3;
- return((char *)adr);
- }
-
- /*
- * Cheat massively because I can't figure out how to read the symbol table
- * properly, so use system("nm ...") to do it instead.
- */
-
- DynamicFunctionList *
- load_symbols(filename, entry_addr)
-
- char *filename;
- int entry_addr;
-
- {
- char command[256];
- char line[128];
- char *tmp_file = "/tmp/PG_DYNSTUFF";
- FILE *fp;
- DynamicFunctionList *head, *scanner;
- int entering = 1, func_addr;
- char funcname[16];
-
- sprintf(command, "/usr/bin/nm %s | grep \' T \' > %s", filename, tmp_file);
-
- if (system(command))
- {
- fprintf(stderr, "system() died\n");
- }
-
- fp = fopen(tmp_file, "r");
-
- while (fgets(line, 127, fp) != NULL)
- {
- sscanf(line, "%lx T %s", &func_addr, funcname);
- if (entering)
- {
- head = (DynamicFunctionList *)
- malloc(sizeof(DynamicFunctionList));
- scanner = head;
- entering = 0;
- }
- else
- {
- scanner->next = (DynamicFunctionList *)
- malloc(sizeof(DynamicFunctionList));
- scanner = scanner->next;
- }
-
- strcpy(scanner->funcname, funcname);
- scanner->func = (func_ptr) (func_addr + entry_addr);
- scanner->next = NULL;
- }
- fclose(fp);
-
- unlink(tmp_file);
- return(head);
- }
-